home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / dialupip / dialupip2.0 / sys / net / if_du.c next >
Encoding:
C/C++ Source or Header  |  1991-01-14  |  27.0 KB  |  1,188 lines

  1. /*
  2. **  Dialup IP driver interface.
  3. **  Based heavily on 4.3 slip driver.
  4. **  Copyright (c) 1991 Bolt Beranek and Newman, Inc.
  5. **  All rights reserved.
  6. **
  7. **  Redistribution and use in source and binary forms are permitted
  8. **  provided that: (1) source distributions retain this entire copyright
  9. **  notice and comment, and (2) distributions including binaries display
  10. **  the following acknowledgement:  ``This product includes software
  11. **  developed by Bolt Beranek and Newman, Inc. and CREN/CSNET'' in the
  12. **  documentation or other materials provided with the distribution and in
  13. **  all advertising materials mentioning features or use of this software.
  14. **  Neither the name of Bolt Beranek and Newman nor CREN/CSNET may be used
  15. **  to endorse or promote products derived from this software without
  16. **  specific prior written permission.
  17. **
  18. **  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  19. **  WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  20. **  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  21. */
  22. #include "du.h"
  23. #if    NDU > 0
  24.  
  25. #define DEBUG
  26.  
  27. #include "../h/param.h"
  28. #include "../h/mbuf.h"
  29. #include "../h/buf.h"
  30. #include "../h/dk.h"
  31. #include "../h/socket.h"
  32. #include "../h/ioctl.h"
  33. #include "../h/file.h"
  34. #include "../h/tty.h"
  35. #include "../h/errno.h"
  36. #include "../net/if.h"
  37. #include "../net/netisr.h"
  38. #include "../net/route.h"
  39. #include "../netinet/in.h"
  40. #include "../netinet/in_systm.h"
  41. #ifdef   vax
  42. #include "../netinet/in_var.h"
  43. #endif    /* vax */
  44. #include "../netinet/ip.h"
  45. #include "../net/if_du.h"
  46. #ifdef    vax
  47. #include "../vax/mtpr.h"
  48. #ifdef    ultrix
  49. #ifndef PRE_ULTRIX_3_0
  50. #include "../rpc/types.h"    /* Needed for Ultrix V3.0 and later    */
  51. #endif    /* PRE_ULTRIX_3_0 */
  52. #endif    /* ultrix */
  53. #endif    /* vax */
  54.  
  55.  
  56.  
  57. /*
  58. **  Shortcuts for use with duioctl.
  59. */
  60. #ifdef    vax
  61. #define DATAVAL(p)        (((struct ifreq *)p)->ifr_data)
  62. #define GET_DATA(p)        DATAVAL(p)
  63. #define SET_DATA(p, d)        DATAVAL(p) = (caddr_t)(d)
  64. #else
  65. #define DATAVAL(p)        (*((int *)p))
  66. #define GET_DATA(p)        DATAVAL(p)
  67. #define SET_DATA(p, d)        DATAVAL(p) = (d)
  68. #endif    /* vax */
  69.  
  70.  
  71. /*
  72. **  DMTU is now a hard limit on the input packet site.  It must be
  73. **  less than CLBYTES - sizeof(struct ifnet *).
  74. */
  75. #define DUMTU        1006
  76.  
  77. /*
  78. **  Timeout parameters and clist usage parameters.
  79. */
  80. #define DU_HZ            5          /* five second granularity */
  81. #define DEFAULT_INACTIVITY_TIME    (60 * 5)    /* 5 minutes */
  82. #define DIAL_MONITORTIMEOUT    (4 * DU_HZ)
  83. #define CLISTRESERVE        (ds->ds_mtu - 6)
  84. #define DU_HIWAT        (ds->ds_mtu - 6)
  85.  
  86.  
  87. /*
  88. **  Escape sequences for framing
  89. */
  90. #define FRAME_END         0xC0        /* Frame End */
  91. #define FRAME_ESCAPE        0xDB        /* Frame Esc */
  92. #define TRANS_FRAME_END         0xDC        /* transposed frame end */
  93. #define TRANS_FRAME_ESCAPE     0xDD        /* transposed frame esc */
  94.  
  95. /*
  96. **  Packet types.
  97. */
  98. #define DUT_IP            03    /* IP packet */
  99. #define DUT_CP            02    /* Control packet */
  100. #define DUT_XX            01    /* Reserved for future use */
  101. #define DUT_EXT            00    /* extended -- leader contains type */
  102.  
  103. /*
  104. **  Line header.
  105. */
  106. struct du_hdr {
  107. #ifdef    vax
  108.     u_char
  109.     duh_hopcnt:4,        /* hop count -- ignored */
  110.     duh_handling:2,        /* routing mechanism used -- ignored */
  111.     duh_type:2;        /* type -- used */
  112. #else
  113.     u_char
  114.     duh_type:2,
  115.     duh_handling:2,
  116.     duh_hopcnt:4;
  117. #endif    /* vax */
  118.     u_char duh_dest;
  119. };
  120.  
  121.  
  122. struct du_softc        du_softc[NDU];
  123. struct globdialstats    globdialstats = { NDU };
  124. int            du_attached = 0;
  125.  
  126. #ifdef    vax
  127. #define t_du T_LINEP
  128. #else
  129. #define t_du t_linep
  130. #endif    /* vax */
  131.  
  132. #ifdef    DEBUG
  133.  
  134. #define D_ICHAR   0x0001
  135. #define D_TIMER   0x0002
  136. #define D_IPKT    0x0004
  137. #define D_OCHAR   0x0008
  138. #define D_OPKT    0x0010
  139. #define D_OUTPUT  0x0020
  140. #define D_INPUT   0x0040
  141. #define D_IOCTL   0x0080
  142. #define D_TRACE   0x0100
  143. #define D_INFO    0x0200
  144.  
  145. int        dial_debug =
  146.     /* D_ICHAR  + */
  147.     /* D_TIMER  + */
  148.     /* D_IPKT   + */
  149.     /* D_OCHAR  + */
  150.     /* D_OPKT   + */
  151.     /* D_OUTPUT + */
  152.     /* D_INPUT  + */
  153.     /* D_IOCTL  + */
  154.     /* D_TRACE  + */
  155.     /* D_INFO   + */
  156.     0;
  157. #define DDEBUG(flag, format, a1, a2, a3)    \
  158.     if ((flag) & dial_debug) printf(format, a1, a2, a3); else
  159. #else
  160. #define DDEBUG(flag, format, a1, a2, a3)    /* NULL */
  161. #endif    /* DEBUG */
  162.  
  163.  
  164. /*
  165. **  du_softc Indexing code
  166. **  See also duattach and dutioctl.
  167. */
  168. #ifdef    SAFE_DU_INDEX
  169. #define DU_Index(ifp)    ((((ifp)->if_name[2] - 'a') * 10) + (ifp)->if_unit)
  170. #else
  171. static int
  172. DU_Index(ifp)
  173.     struct ifnet *ifp;
  174. {
  175.     register char *p;
  176.     int i;
  177.  
  178.     /* Check to see if the input looks real or not */
  179.     p = ifp->if_name;
  180.     if (p[0] != 'd' || p[1] != 'u'
  181.      || p[2] < 'a' || p[2] > 'z' || p[3] != 0
  182.      || ifp->if_unit < 0 || ifp->if_unit > 9) {
  183.     printf("DU_Index: WARNING: struct ifnet ifp is not a du interface.\n");
  184.     printf("DU_Index:          Interface is \"%s\", Unit is %d\n",
  185.         ifp->if_name, ifp->if_unit);
  186.     return(0);        /* XXX Panic? */
  187.     }
  188.  
  189.     i = ((p[2] - 'a') * 10) + ifp->if_unit;
  190.     DDEBUG(D_INFO, "DU_Index: if_name = \"%s\", if_unit = %d, index = %d\n",
  191.     ifp->if_name, ifp->if_unit, i);
  192.     return(i);
  193. }
  194. #endif    /* SAFE_DU_INDEX */
  195.  
  196. int duoutput(), duioctl(), dutimer();
  197.  
  198.  
  199.  
  200. /*
  201. ** TTY LINE DISCIPLINE ROUTINES
  202. */
  203.  
  204. /*
  205. **  Open line.
  206. */
  207. /* ARGSUSED */
  208. dutopen(dev, tp)
  209.     dev_t dev;
  210.     register struct tty *tp;
  211. {
  212.     DDEBUG(D_OUTPUT, "dutopen line %d\n", tp->t_dev, 0, 0);
  213.     if (!suser())
  214.     return(EPERM);
  215.  
  216.     if (tp->t_line == DUDISC)
  217.     return(EBUSY);
  218.  
  219.     /* Unlike SLIP, we don't attach here. */
  220.     return(0);
  221. }
  222.  
  223.  
  224. /*
  225. **  Close line.  Detach the tty from the du.  Mimics part of ttyclose().
  226. */
  227. dutclose(tp)
  228.     struct tty *tp;
  229. {
  230.     DDEBUG(D_TRACE, "dutclose line %x\n", tp->t_dev, 0, 0);
  231.     ttywflush(tp);
  232.     tp->t_line = 0;
  233.     if (tp->t_du) {
  234.     dutnetclose(tp->t_du);
  235.     tp->t_du = NULL;
  236.     }
  237. }
  238.  
  239.  
  240. /*
  241. **  Clean up the net interface when a connection is closed or abandoned.
  242. **  This is separate from dutclose since we may not have a line when we
  243. **  call this.
  244. */
  245. dutnetclose(ds)
  246.     struct du_softc *ds;
  247. {
  248.     struct mbuf *m;
  249.     int s;
  250.  
  251. #ifdef    DEBUG
  252.     if (ds)
  253.     DDEBUG(D_TRACE, "dutnetclose ds %x dstty %x\n", ds, ds->ds_ttyp, 0);
  254.     else
  255.     DDEBUG(D_TRACE, "dutnetclose ds %x\n", ds, 0, 0);
  256. #endif    /* DEBUG */
  257.  
  258.     if (ds) {
  259.     s = splimp();            /* paranoid; splnet probably ok */
  260.     /* inactive line */
  261.     ds->ds_flags &= ~(DS_LWAITING|DS_LACTIVE|DS_LDOWN|DS_FAILCALL);
  262.     if (ds->ds_ttyp)
  263.         ds->ds_ttyp->t_du = NULL;
  264.  
  265.     if (ds->ds_buf) {
  266. #ifdef    vax
  267. #ifdef    ultrix
  268. #ifndef    PRE_ULTRIX_3_0
  269.             kmem_free((caddr_t)ds->ds_buf, KM_DEVBUF);
  270. #else
  271.             km_free((caddr_t)ds->ds_buf, ds->ds_mtu);
  272. #endif    /* PRE_ULTRIX_3_0 */
  273. #else
  274.         /* BSD */
  275.         MCLFREE((struct mbuf *)ds->ds_buf);
  276. #endif    /* ultrix */
  277. #else    /* sun */
  278.         kmem_free((caddr_t)ds->ds_buf, ds->ds_mtu);
  279. #endif    /* vax */
  280.         ds->ds_buf = NULL;
  281.     }
  282.  
  283.     /* Clear queues. */
  284.     while (ds->ds_if.if_snd.ifq_len > 0) {
  285.         IF_DEQUEUE(&ds->ds_if.if_snd, m);
  286.         IF_DROP(&ds->ds_if.if_snd);
  287.         m_freem(m);
  288.     }
  289.     splx(s);
  290.  
  291.     if (ds->ds_ttyp) {
  292.         /* tell application to go away */
  293.         DDEBUG(D_TRACE, "netclose: sending signal %d\n",
  294.         ds->ds_ttyp->t_pgrp, 0, 0);
  295.         gsignal(ds->ds_ttyp->t_pgrp, SIGHUP);
  296.         gsignal(ds->ds_ttyp->t_pgrp, SIGCONT);
  297.         ds->ds_ttyp = NULL;
  298.     }
  299.     }
  300. }
  301.  
  302.  
  303. /*
  304. **  Handle modem state changes; basically line drops.
  305. */
  306. dutmodem(tp, flag)
  307.     register struct tty *tp;
  308.     int flag;
  309. {
  310.     DDEBUG(D_TRACE, "dutmodem (Did we lose carrier?)\n", 0, 0, 0);
  311.     if (!flag) {
  312.     /* Lost carrier. */
  313.     tp->t_state &= ~TS_CARR_ON;
  314.     if (tp->t_state & TS_ISOPEN && !(tp->t_flags & NOHANG)) {
  315.         DDEBUG(D_TRACE, "dutmodem kill %d\n", tp->t_pgrp, 0, 0);
  316.         gsignal(tp->t_pgrp, SIGHUP);
  317.         gsignal(tp->t_pgrp, SIGCONT);
  318.         return(0);
  319.     }
  320.     }
  321.     else {
  322.     /* Carrier now on. */
  323.     tp->t_state |= TS_CARR_ON;
  324.     }
  325.     return(1);
  326. }
  327.  
  328. /*
  329. **  IOCTL.  Attach to TTY, get unit number.
  330. */
  331. /* ARGSUSED */
  332. dutioctl(tp, cmd, data, flag)
  333.     struct tty *tp;
  334.     int cmd;
  335.     caddr_t data;
  336.     int flag;
  337. {
  338.     struct ifreq *ifr;
  339.     struct du_softc *ds;
  340.     register char *p;
  341.     int metric;
  342.  
  343.     DDEBUG(D_TRACE, "dutioctl: line %d cmd 0x%x\n", tp->t_dev, cmd, 0);
  344.     if (tp == NULL)
  345.     return(ENOTTY);
  346.  
  347.     if (!du_attached) {
  348.     printf("dutioctl: Used du device before attach\n");
  349.     return (EINVAL);
  350.     }
  351.  
  352.     switch (cmd) {
  353.     case SIOCSIFADDR:
  354.     ifr = (struct ifreq *)data;
  355.     p = ifr->ifr_name;
  356.     /* Does this have the correct form? */
  357.     if (p[0] != 'd' || p[1] != 'u'
  358.      || p[2] < 'a' || p[2] > 'z' || p[3] < '0' || p[3] > '9'
  359.      || p[4] != '\0') {
  360.         DDEBUG(D_IOCTL, "dutioctl: Bad du device \"%s\"\n", p, 0, 0);
  361.         return(EINVAL);
  362.     }
  363.  
  364.     /* Extract the index and verify. */
  365.     DDEBUG(D_IOCTL, "dutioctl: du device name = \"%s\"\n", p, 0, 0);
  366.     metric = ((p[2] - 'a') * 10) + (p[3] - '0');
  367.     DDEBUG(D_IOCTL, "dutioctl: name %s metric %d\n", p, metric, 0);
  368.     if (metric < 0 || metric >= NDU)
  369.         return(EINVAL);
  370.     ds = &du_softc[metric];
  371.  
  372.     /* already busy */
  373.     if (ds->ds_flags & DS_LACTIVE)
  374.         return(EIO);
  375.     if (duinit(ds) == 0)
  376.         return(ENOBUFS);
  377.  
  378.     ds->ds_ilen = 0;
  379.     tp->t_du = (caddr_t)ds;
  380.     /* flush out the line */
  381.     ttyflush(tp, FREAD|FWRITE);
  382.  
  383.     ds->ds_flags |= DS_LACTIVE;
  384.     ds->ds_flags &= ~DS_LWAITING;
  385.     ds->ds_timer = ds->ds_atimo;
  386.     ds->ds_if.if_timer = DU_HZ;
  387.     /* and try to start I/O on device */
  388.     ds->ds_ttyp = tp;
  389.     ds->ds_if.if_flags |= IFF_UP;
  390.  
  391.     dutstart(ds->ds_ttyp);
  392.     return(0);
  393.  
  394.     /* slip uses this to get device number, do we care? */
  395.     case TIOCGETD:
  396.     *(int *)data = DU_Index(&((struct du_softc *)tp->t_du)->ds_if);
  397.     return(0);
  398.     }
  399.     return(-1);
  400. }
  401.  
  402.  
  403. /*
  404. **  Copy data buffer to mbuf chain leave space for interface pointer.
  405. */
  406. struct mbuf *
  407. du_btom(ds, len)
  408.     struct du_softc *ds;
  409.     register int len;
  410. {
  411.     register caddr_t cp;
  412.     register struct mbuf *m, **mp;
  413.     register unsigned int count;
  414.     int first;
  415.     struct mbuf *top;
  416.  
  417.     first = 1;
  418.     top = NULL;
  419.     for (cp = ds->ds_buf, mp = ⊤ len > 0; mp = &m->m_next, len -= count) {
  420.     MGET(m, M_DONTWAIT, MT_DATA);
  421.     if ((*mp = m) == NULL) {
  422.         m_freem(top);
  423.         return(NULL);
  424.     }
  425. #ifdef    BSD
  426.     if (first) {
  427.         m->m_off += sizeof(struct ifnet *);
  428.         count = MIN(len, MLEN - sizeof(struct ifnet *));
  429.         first = 0;
  430.     }
  431.     else
  432. #endif    /* BSD */
  433.         count = MIN(len, MLEN);
  434.     bcopy(cp, mtod(m, caddr_t), count);
  435.     m->m_len = count;
  436.     cp += count;
  437.     }
  438.  
  439.     return(top);
  440. }
  441.  
  442.  
  443. /*
  444. **  Receiver interrupt.
  445. */
  446. dutinput(c, tp)
  447.     register int c;
  448.     register struct tty *tp;
  449. {
  450.     register struct du_softc *ds;
  451.     register struct mbuf *m;
  452.     struct du_hdr ldr;
  453.     int s;
  454.  
  455.     DDEBUG(D_ICHAR, "dutinput\n", 0, 0, 0);
  456.     tk_nin++;
  457.  
  458.     /* Handle spurious interrupts before the SIOCSIFADDR is done. */
  459.     ds = (struct du_softc *)tp->t_du;
  460.     if (ds < &du_softc[0] || ds > &du_softc[NDU])
  461.     return;
  462.  
  463.     DDEBUG(D_INPUT,"dutinput tp = x%x\n", tp, 0, 0);
  464.     if (ds == NULL || !(ds->ds_flags & DS_LACTIVE))
  465.     return;
  466.  
  467.     ds->ds_cchr++;
  468.  
  469.     c &= 0xFF;
  470.     DDEBUG(D_ICHAR, "dutinput flags %x len %d c= x%x\n",
  471.     ds->ds_flags, ds->ds_ilen, c);
  472.     if (ds->ds_flags & DS_ESCAPED) {
  473.     ds->ds_flags &= ~DS_ESCAPED;
  474.     switch (c) {
  475.     default:
  476.         ds->ds_if.if_ierrors++;
  477.         ds->ds_mp = ds->ds_buf;
  478.         ds->ds_ilen = 0;
  479.         return;
  480.     case TRANS_FRAME_ESCAPE:
  481.         ds->ds_resc++;
  482.         c = FRAME_ESCAPE;
  483.         break;
  484.     case TRANS_FRAME_END:
  485.         ds->ds_resc++;
  486.         c = FRAME_END;
  487.         break;
  488.     }
  489.     }
  490.     else {
  491.     switch (c) {
  492.     case FRAME_END:
  493.         if (ds->ds_ilen == 0)
  494.         return;
  495.         m = du_btom(ds, ds->ds_ilen);
  496.         if (m == NULL) {
  497.         ds->ds_if.if_ierrors++;
  498.         return;
  499.         }
  500.         ds->ds_mp = ds->ds_buf;
  501.         ds->ds_ilen = 0;
  502.         ds->ds_if.if_ipackets++;
  503.         globdialstats.gds_ipln++;
  504. #ifdef    BSD
  505.         *mtod(m, struct ifnet**) = &ds->ds_if;
  506. #endif    /* BSD */
  507.         DDEBUG(D_INPUT,"dutinput: IP PKT\n", 0, 0, 0);
  508.         globdialstats.gds_opup++;
  509.         ds->ds_cpsip++;
  510.         s = splimp();
  511.         if (IF_QFULL(&ipintrq)) {
  512.         IF_DROP(&ipintrq);
  513.         ds->ds_if.if_ierrors++;
  514.         m_freem(m);
  515.         }
  516.         else {
  517.         IF_ENQUEUE(&ipintrq, m);
  518.         schednetisr(NETISR_IP);
  519.         }
  520.         ds->ds_timer = ds->ds_atimo;
  521.         splx(s);
  522.         return;
  523.     case FRAME_ESCAPE:
  524.         ds->ds_flags |= DS_ESCAPED;
  525.         return;
  526.     }
  527.     }
  528.  
  529.     if (++ds->ds_ilen > ds->ds_mtu) {
  530.     ds->ds_if.if_ierrors++;
  531.     ds->ds_mp = ds->ds_buf;
  532.     ds->ds_ilen = 0;
  533.     return;
  534.     }
  535.  
  536.     *ds->ds_mp++ = c;
  537. }
  538.  
  539.  
  540.  
  541. /*
  542. **  Start output on interface.  Get another datagram to send from the
  543. **  interface queue and map it to the interface before starting output.
  544. */
  545. dutstart(tp)
  546.     register struct tty *tp;
  547. {
  548.     register struct du_softc *ds;
  549.     register struct mbuf *m;
  550.     register int len;
  551.     register u_char *cp;
  552.     int flush, nd, np, n, s;
  553.     struct mbuf *m2;
  554.     extern int cfreecount;
  555.  
  556.     if (tp == NULL)
  557.     return(ENOTTY);
  558.  
  559.     ds = (struct du_softc *)tp->t_du;
  560.     DDEBUG(D_TRACE, "dutstart for \"%s%d\" nc = %d\n",
  561.     ds->ds_if.if_name, ds->ds_if.if_unit, tp->t_outq.c_cc);
  562.  
  563.     for ( ; ; ) {
  564.     /* If there is more in the output queue, just send it now.  We are
  565.      * being called in lieu of ttstart and must do what it would. */
  566.     if (tp->t_outq.c_cc > 0)
  567.         ttstart(tp);
  568.     if (tp->t_outq.c_cc > DU_HIWAT)
  569.         return;
  570.     /* This happens briefly when the line shuts down. */
  571.     if (ds == NULL) {
  572.         DDEBUG(D_TRACE, "dutstart null ds (not an error)\n", 0, 0, 0);
  573.         return;
  574.     }
  575.  
  576.     /* If system is getting low on clists and we have something
  577.      * running already, stop here. */
  578.     if (cfreecount < CLISTRESERVE + ds->ds_mtu) {
  579.         DDEBUG(D_TRACE, "clists = %d\n", cfreecount, 0, 0);
  580.         ds->ds_flags &= ~DS_OACTIVE;
  581.         /* If the free clist is empty, try to bring things back up to
  582.          * the low water mark.  Do our fair share.  */
  583.         if (cfreecount == 0) {
  584.         DDEBUG(D_TRACE, "No clists, dumping some packets\n", 0, 0, 0);
  585.         s = splimp();
  586.         /* dequeue the pkts and hand back the mbufs */
  587.         while (ds->ds_if.if_snd.ifq_len
  588.          && cfreecount < CLISTRESERVE + ds->ds_mtu) {
  589.             IF_DEQUEUE(&ds->ds_if.if_snd, m);
  590.             IF_DROP(&ds->ds_if.if_snd);
  591.             if (m)
  592.             m_freem(m);
  593.         }
  594.         ds->ds_flags |= DS_OACTIVE;
  595.         splx(s);
  596.         }
  597.         return;
  598.     }
  599.  
  600.     /* Get a packet and send it to the interface. */
  601.     DDEBUG(D_OUTPUT, "Getting a packet\n", 0, 0, 0);
  602.     s = splimp();
  603.     IF_DEQUEUE(&ds->ds_if.if_snd, m);
  604.     if (m == NULL) {
  605.         if (tp->t_outq.c_cc == 0) {
  606.         ds->ds_flags &= ~DS_OACTIVE;
  607.         ds->ds_timer = ds->ds_atimo;
  608.         ds->ds_if.if_timer = DU_HZ;
  609.         }
  610.         splx(s);
  611.         DDEBUG(D_OUTPUT, "null mbuf\n", 0, 0, 0);
  612.         return;
  613.     }
  614.     flush = !(ds->ds_flags & DS_OACTIVE);
  615.     ds->ds_flags |= DS_OACTIVE;
  616.     ds->ds_timer = -1;
  617.     ds->ds_if.if_timer = 0;
  618.     splx(s);
  619.     /* The extra FRAME_END will start up a new packet, and thus
  620.      * will flush any accumulated garbage.  We do this whenever
  621.      * the line may have been idle for some time. */
  622.     if (flush) {
  623.         DDEBUG(D_OCHAR,"dutstart: Frame End\n", 0, 0, 0);
  624.         (void) putc(FRAME_END, &tp->t_outq);
  625.         ds->ds_cchs++;    /* one for frame END */
  626.     }
  627.  
  628.     while (m) {
  629.         DDEBUG(D_OUTPUT, "M\n", 0, 0, 0);
  630.         cp = mtod(m, u_char *);
  631.         for (len = m->m_len, ds->ds_cchs += len; len > 0; ) {
  632.         /* Find out how many bytes in the string we can
  633.          * handle without doing something special. */
  634.         nd = locc(FRAME_ESCAPE, len, cp);
  635.         np = locc(FRAME_END, len, cp);
  636.         n = len - MAX(nd, np);
  637.         if (n) {
  638.             /* Put n characters at once into the tty output queue. */
  639.             if (b_to_q((char *)cp, n, &tp->t_outq))
  640.             break;
  641.             len -= n;
  642.             cp += n;
  643.         }
  644.         /* If there are characters left in the mbuf, the first
  645.          * one must be special -- put it out in a different form. */
  646.         if (len) {
  647.             DDEBUG(D_OCHAR,"dutstart: FRAME_ESC\n", 0, 0, 0);
  648.             if (putc(FRAME_ESCAPE, &tp->t_outq))
  649.             break;
  650.             DDEBUG(D_OCHAR, "dutstart: *cp = x%02x\n", *cp, 0, 0);
  651.             ds->ds_sesc++;
  652.             if (putc(*cp == FRAME_ESCAPE ? TRANS_FRAME_ESCAPE :
  653.                 TRANS_FRAME_END, &tp->t_outq)) {
  654.             (void)unputc(&tp->t_outq);
  655.             break;
  656.             }
  657.             ds->ds_cchs += 2;  /* one for ESC one for char */
  658.             cp++;
  659.             len--;
  660.         }
  661.         }
  662.         MFREE(m, m2);
  663.         m = m2;
  664.     }
  665.     DDEBUG(D_OPKT|D_OUTPUT, "ENDM\n", 0, 0, 0);
  666.     if (putc(FRAME_END, &tp->t_outq)) {
  667.         /* No room.  Remove a char to make room and end the packet
  668.          * normally.  If you get many collisions (more than one or two
  669.          * a day) you probably do not have enough clists. */
  670.         (void)unputc(&tp->t_outq);
  671.         (void)putc(FRAME_END, &tp->t_outq);
  672.         ds->ds_if.if_collisions++;
  673.     }
  674.     else {
  675.         ds->ds_if.if_opackets++;
  676.         globdialstats.gds_opln++;
  677.         ds->ds_cchs++;    /* one for FRAME_END */
  678.     }
  679.     }
  680. }
  681.  
  682.  
  683.  
  684. /*
  685. **  DU INTERFACE ROUTINES
  686. */
  687. duattach(net)
  688.     int net;
  689. {
  690.     static char du_names[(NDU / 10) + 1][4];
  691.     register struct du_softc *ds;
  692.     register int i;
  693.  
  694.     DDEBUG(D_TRACE, "duattach entered\n", 0, 0, 0);
  695.     if (du_attached)
  696.     return;
  697.     du_attached = 1;
  698.  
  699.     /* Initialize the names (hard coded into dutioctl() also). */
  700.     for (i = 0; i <= NDU / 10; i++) {
  701.         du_names[i][0] = 'd';
  702.     du_names[i][1] = 'u';
  703.     du_names[i][2] = 'a' + i;
  704.     du_names[i][3] = '\0';
  705.     }
  706.  
  707.     /* Initialize the slots. */
  708.     for (i = 0; i < NDU; i++) {
  709.     ds = &du_softc[i];
  710.     /* set up timer information -- wait for connection to time out. */
  711.     ds->ds_atimo = DEFAULT_INACTIVITY_TIME/DU_HZ;
  712.     ds->ds_wtimo = 12 * DU_HZ;
  713.     ds->ds_timer = -1;
  714.  
  715.     /* Fill in if structure. */
  716.     ds->ds_if.if_name = du_names[i / 10];
  717.     ds->ds_if.if_unit = i % 10;
  718.     ds->ds_if.if_mtu = ds->ds_mtu = DUMTU;
  719.     ds->ds_if.if_flags = IFF_POINTOPOINT;
  720.     ds->ds_if.if_ioctl = duioctl;
  721.     ds->ds_if.if_output = duoutput;
  722.     /* We need a larger queue because of the startup delay. */
  723.     ds->ds_if.if_snd.ifq_maxlen = 2 * IFQ_MAXLEN;
  724.     ds->ds_if.if_watchdog = dutimer;
  725.     ds->ds_if.if_timer = 0;
  726.     if_attach(&ds->ds_if);
  727.     DDEBUG(D_TRACE, "duattach adding unit %s%d at 0x%x\n",
  728.         ds->ds_if.if_name, ds->ds_if.if_unit, &ds->ds_if);
  729.     }
  730. }
  731.  
  732.  
  733. /*
  734. **  Queue a packet.  Start transmission if not active.
  735. */
  736. duoutput(ifp, m, dst)
  737.     register struct ifnet *ifp;
  738.     register struct mbuf *m;
  739.     struct sockaddr *dst;
  740. {
  741.     register struct du_softc *ds;
  742.     register struct mbuf *tmpm;
  743.     struct du_hdr leader;
  744.     int s;
  745.  
  746.     DDEBUG(D_TRACE, "duoutput for \"%s%d\"\n", ifp->if_name, ifp->if_unit, 0);
  747.     globdialstats.gds_ipup++;
  748.  
  749.     /* Check address family. */
  750.     if (dst->sa_family != AF_INET) {
  751.     printf("duoutput: \"%s%d\": AF %d not supported\n",
  752.         ifp->if_name, ifp->if_unit, dst->sa_family);
  753.     m_freem(m);
  754.     return(EAFNOSUPPORT);
  755.     }
  756.  
  757.     /* check family and build our leader. */
  758.     bzero((caddr_t)&leader, sizeof leader);
  759.     ds = &du_softc[DU_Index(ifp)];
  760.     ds->ds_cprip++;
  761.     leader.duh_type = DUT_IP;
  762.     DDEBUG(D_OUTPUT, "dutoutput flags %x\n",ds->ds_flags, 0, 0);
  763.  
  764.     if (!(ds->ds_if.if_flags & IFF_UP)) {
  765.     m_freem(m);
  766.     return(EHOSTUNREACH);
  767.     }
  768.     if ((ds->ds_flags & DS_FAILCALL)) {
  769.     m_freem(m);
  770.     return(ENETDOWN);
  771.     }
  772.  
  773.     if (!(ds->ds_flags & (DS_LWAITING|DS_LACTIVE|DS_LDOWN|DS_FAILCALL))) {
  774.     if (!(ds->ds_flags & DS_ENABLECALL)) {
  775.         m_freem(m);
  776.         return(ENETDOWN);
  777.     }
  778.     /* Not waiting and not active -- eventually make unit
  779.      * correspond to family. */
  780.     if ((tmpm = m_pullup(m, sizeof(struct ip))) == NULL) {
  781.         printf("m_pullup failed in duoutput\n");
  782.         return(0);
  783.     }
  784.  
  785.     /* get address of other end of p-to-p link */
  786.     m = tmpm;
  787.     if (dialupreq(mtod(m, struct ip *),
  788. #ifdef    vax
  789.         (struct sockaddr_in*)&ifp->if_addrlist->ifa_dstaddr,
  790. #else
  791.         (struct sockaddr_in*)&ifp->if_dstaddr,
  792. #endif    /* vax */
  793.         ifp->if_name, ifp->if_unit, 1)) {
  794.         m_freem(m);
  795.         return(EHOSTUNREACH);
  796.     }
  797.  
  798.     ds->ds_flags |= DS_LWAITING;
  799.     ds->ds_timer = ds->ds_wtimo;
  800.     ds->ds_if.if_timer = DU_HZ;
  801.     }
  802.  
  803.     /* now queue */
  804.     s = splimp();
  805.     if (IF_QFULL(&ifp->if_snd)) {
  806.     IF_DROP(&ifp->if_snd);
  807.     splx(s);
  808.     m_freem(m);
  809.     ds->ds_if.if_oerrors++;
  810.     return(ENOBUFS);
  811.     }
  812.     IF_ENQUEUE(&ifp->if_snd, m);
  813.     splx(s);
  814.  
  815.     /* If line is up and no activity, start something */
  816.     if ((ds->ds_flags & DS_LACTIVE) && !(ds->ds_flags & DS_OACTIVE)) {
  817.     if (ds->ds_ttyp == NULL)
  818.         panic("duoutput no tty");
  819.  
  820.     if (!(ds->ds_ttyp->t_state & TS_CARR_ON)) {
  821.         DDEBUG(D_TRACE, "duoutput Carrier Loss.\n", 0, 0, 0);
  822.         dutnetclose(ds);
  823.         return(EHOSTUNREACH);
  824.     }
  825.     dutstart(ds->ds_ttyp);
  826.     }
  827.     return(0);
  828. }
  829.  
  830.  
  831. duinit(ds)
  832.     register struct du_softc *ds;
  833. {
  834. #ifdef    vax
  835. #ifdef    ultrix
  836. #ifdef    PRE_ULTRIX_3_0
  837.     caddr_t km_alloc();
  838. #endif    /* PRE_ULTRIX_3_0 */
  839.     caddr_t p;
  840. #else
  841.     struct mbuf *p;
  842. #endif    /* ultrix */
  843. #else
  844.     caddr_t kmem_alloc();
  845.     caddr_t p;
  846. #endif    /* vax */
  847.  
  848.     DDEBUG(D_TRACE, "duinit: ds %x\n", ds, 0, 0);
  849.     if (ds->ds_buf == NULL) {
  850. #ifdef    vax
  851. #ifdef    ultrix
  852. #ifdef    PRE_ULTRIX_3_0
  853.     p = km_alloc(ds->ds_mtu);
  854. #else
  855.     kmem_alloc(p, caddr_t, ds->ds_mtu, KM_DEVBUF);
  856. #endif    /* PRE_ULTRIX_3_0 */
  857. #else
  858.     MCLALLOC(p, 1);
  859. #endif    /* ultrix */
  860. #else
  861.     p = kmem_alloc(ds->ds_mtu);
  862. #endif    /* vax */
  863.  
  864.     if (p == NULL) {
  865.         printf("du%d: can't allocate buffer\n", ds - du_softc);
  866.         ds->ds_if.if_flags &= ~IFF_UP;
  867.         return(0);
  868.     }
  869.     ds->ds_buf = (char *)p;
  870.     ds->ds_mp = ds->ds_buf;
  871.     }
  872.     return(1);
  873. }
  874.  
  875.  
  876.  
  877. /*
  878. **  Monitor routine that records CPU state.
  879. */
  880. dialmonitor()
  881. {
  882.     register struct du_softc *ds;
  883.  
  884.     for (ds = du_softc; ds < &du_softc[NDU]; ds++) {
  885.     if (!(ds->ds_flags & DS_MONITORON) || ds->ds_ttyp == NULL)
  886.         continue;
  887.     if (ds->ds_ttyp->t_state & TS_BUSY)
  888.         ds->ds_ctpbusy++;
  889.     else
  890.         ds->ds_ctpidle++;
  891.     }
  892.     timeout(dialmonitor, (caddr_t)NULL, DIAL_MONITORTIMEOUT);
  893. }
  894.  
  895.  
  896. /*
  897. **  IOCTL
  898. */
  899. duioctl(ifp, cmd, data, flags)
  900. register struct ifnet *ifp;
  901. int cmd;
  902. caddr_t data;
  903. int flags;
  904. {
  905.     register struct sockaddr_in *sin;
  906.     int s;
  907.     int error;
  908.     struct du_softc *ds;
  909.  
  910. #ifdef    vax
  911.     sin = (struct sockaddr_in *)&((struct ifaddr *)data)->ifa_addr;
  912. #else  /* vax */
  913.     sin = (struct sockaddr_in *)data;
  914. #endif    /* vax */
  915.  
  916.     DDEBUG(D_TRACE, "duioctl: \"%s%d\"  cmd = 0x%x\n",
  917.         ifp->if_name, ifp->if_unit, cmd);
  918.     DDEBUG(D_TRACE, "duioctl: \"%s%d\" data = 0x%x\n",
  919.         ifp->if_name, ifp->if_unit, data);
  920.  
  921.     error = 0;
  922.     ds = &du_softc[DU_Index(ifp)];
  923.     switch (cmd) {
  924.  
  925.     default:
  926.     error = EINVAL;
  927.  
  928.     case SIOCSIFADDR:
  929.     DDEBUG(D_IOCTL, "duioctl SIOCSIFADDR addr (0x%x)\n",
  930.         sin->sin_addr.s_addr, 0, 0);
  931. #ifdef    vax
  932.     DDEBUG(D_IOCTL, "duioctl name %s addr (0x%x) dstaddr (0x%x)\n",
  933.     ifp->if_name,
  934.     ((struct sockaddr_in *)&ifp->if_addrlist->ifa_addr)->sin_addr.s_addr,
  935.     ((struct sockaddr_in*)&ifp->if_addrlist->ifa_dstaddr)->sin_addr.s_addr);
  936. #endif    /* vax */
  937.  
  938.     if (sin->sin_family != AF_INET) {
  939.         error = EAFNOSUPPORT;
  940.         break;
  941.     }
  942. #ifdef    vax
  943.     ifp->if_flags |= IFF_UP;
  944. #else
  945.     /* clear current route, set new address  */
  946.     if_rtinit(ifp, -1);
  947.     ifp->if_addr = *(struct sockaddr *)data;
  948.     ifp->if_net = in_netof(sin->sin_addr);
  949.     ifp->if_flags |= IFF_UP | IFF_RUNNING;
  950.  
  951.     /* Set up routing entry. */
  952.     if (!(ifp->if_flags & IFF_ROUTE)) {
  953.         rtinit(&ifp->if_dstaddr, &ifp->if_addr,
  954.         RTF_HOST|RTF_GATEWAY|RTF_UP);
  955.         ifp->if_flags |= IFF_ROUTE;
  956.     }
  957. #endif    /* vax */
  958.     ds->ds_flags |= DS_MONITORON | DS_ENABLECALL;
  959.     timeout(dialmonitor, (caddr_t)NULL, DIAL_MONITORTIMEOUT);
  960.     break;
  961.  
  962.     case SIOCSIFDSTADDR:
  963.     if (sin->sin_family != AF_INET)
  964.         error = EAFNOSUPPORT;
  965.     break;
  966.  
  967.     case SIOCFAILCALL:
  968.     s = splimp();
  969.     /* Flush any waiting packets. */
  970.     if (ds->ds_flags & DS_LWAITING) {
  971.         while (ds->ds_if.if_snd.ifq_len) {
  972.         register struct mbuf *m;
  973.  
  974.         IF_DEQUEUE(&ds->ds_if.if_snd,m);
  975.         IF_DROP(&ds->ds_if.if_snd);
  976.         if (m)
  977.             m_freem(m);
  978.         }
  979.         ds->ds_flags &= ~(DS_LWAITING|DS_LACTIVE|DS_LDOWN);
  980.         ds->ds_flags |= DS_FAILCALL;
  981.         ds->ds_timer = ds->ds_atimo;
  982.         ds->ds_if.if_timer = DU_HZ;
  983.     }
  984.     splx(s);
  985.     break;
  986.  
  987.     case SIOCSATIMEO:
  988.     ds->ds_atimo = (u_long)GET_DATA(data) / DU_HZ;
  989.     break;
  990.  
  991.     case SIOCGATIMEO:
  992.     SET_DATA(data, (ds->ds_atimo * DU_HZ));
  993.     break;
  994.  
  995.     case SIOCSWTIMEO:
  996.     ds->ds_wtimo = (u_long)GET_DATA(data) / DU_HZ;
  997.     break;
  998.  
  999.     case SIOCGWTIMEO:
  1000.     SET_DATA(data, (ds->ds_wtimo * DU_HZ));
  1001.     break;
  1002.  
  1003.     case SIOCSSOFTTIMER:
  1004.     s = splimp();
  1005.     ds->ds_timer = (u_long)GET_DATA(data);
  1006.     splx(s);
  1007.     break;
  1008.  
  1009.     case SIOCSSOFTFLAGS:
  1010.     s = splimp();
  1011.     ds->ds_flags = (int)GET_DATA(data);
  1012.     splx(s);
  1013.     break;    
  1014.  
  1015.     case SIOCGSOFTFLAGS:
  1016.     s = splimp();
  1017.     SET_DATA(data, ds->ds_flags);
  1018.     splx(s);
  1019.     break;
  1020.  
  1021.     case SIOCGIPKTS:
  1022.     s = splimp();
  1023.     SET_DATA(data, ifp->if_ipackets);
  1024.     splx(s);
  1025.     break;
  1026.  
  1027.     case SIOCGOPKTS:
  1028.     s = splimp();
  1029.     SET_DATA(data, ifp->if_opackets);
  1030.     splx(s);
  1031.     break;
  1032.  
  1033.     case SIOCCLEARQ:
  1034.     s = splimp();
  1035.     /* dequeue the pkts and hand back the mbufs */
  1036.     while (ds->ds_if.if_snd.ifq_len) {
  1037.         struct mbuf *m;
  1038.  
  1039.         IF_DEQUEUE(&ds->ds_if.if_snd,m);
  1040.         IF_DROP(&ds->ds_if.if_snd);
  1041.         if (m)
  1042.         m_freem(m);
  1043.     }
  1044.     splx(s);
  1045.     break;    
  1046.  
  1047.     case SIOCGIFMTU:
  1048.     SET_DATA(data, ds->ds_mtu);
  1049.     break;
  1050.  
  1051.     case SIOCSIFMTU:
  1052.     error = EBUSY;        /* XXX */
  1053.     break;
  1054.  
  1055.     case SIOCBRINGUP:
  1056.     {
  1057.         struct ip ipfill;
  1058.         struct sockaddr_in sinfill;
  1059.  
  1060.         if (dialupreq(&ipfill, &sinfill, ifp->if_name, ifp->if_unit, 0)) {
  1061.         error = EHOSTUNREACH;
  1062.         break;
  1063.         }
  1064.         ds->ds_flags |= DS_LWAITING;
  1065.         ds->ds_timer = ds->ds_wtimo;
  1066.         ds->ds_if.if_timer = DU_HZ;
  1067.         /* If line is up and no activity, start something */
  1068.         if ((ds->ds_flags & DS_LACTIVE) && !(ds->ds_flags & DS_OACTIVE)) {
  1069.         if (ds->ds_ttyp == NULL)
  1070.             panic("duioctl no tty");
  1071.  
  1072.         if (!(ds->ds_ttyp->t_state & TS_CARR_ON)) {
  1073.             DDEBUG(D_TRACE, "duioctl Carrier Loss.\n", 0, 0, 0);
  1074.             dutnetclose(ds);
  1075.             error = EHOSTUNREACH;
  1076.         }
  1077.         dutstart(ds->ds_ttyp);
  1078.         }
  1079.     }
  1080.     }
  1081.     DDEBUG(D_IOCTL, "duioctl return(%d)\n", error, 0, 0);
  1082.     return(error);
  1083. }
  1084.  
  1085.  
  1086. /*
  1087. **  Watchdog timer.
  1088. **  Must figure out which interface timed out, since we only get a
  1089. **  unit number.
  1090. */
  1091. dutimer(unit)
  1092.     int unit;
  1093. {
  1094.     struct du_softc *ds;
  1095.     register int i;
  1096.     register int s;
  1097.  
  1098.     DDEBUG(D_TRACE, "dutimer: unit = %d\n", unit, 0, 0);
  1099.  
  1100.     if (unit < 0 || unit > 9)
  1101.     return;
  1102.     for (i = unit; i < NDU; i += 10) {
  1103.     if (i >= NDU)
  1104.         return;
  1105.  
  1106.     /* Test to see if this is the correct interface. */
  1107.     ds = &du_softc[i];
  1108.  
  1109.     DDEBUG(D_TIMER, "dutimer: unit %d, flags %x timer %d",
  1110.         i, (int)ds->ds_flags, (int)ds->ds_timer);
  1111.     DDEBUG(D_TIMER, "timer %d, if_timer %d, qlen %d\n",
  1112.         (int)ds->ds_if.if_timer, ds->ds_if.if_snd.ifq_len, 0);
  1113.  
  1114.     /* Is this the interface we want? */
  1115.     if (ds->ds_if.if_timer || ds->ds_timer <= 0)
  1116.         continue;
  1117.  
  1118.     /* just being cautious by setting up the interrupt priority */
  1119.     s = splimp();
  1120.     if (ds->ds_timer > 0 && --(ds->ds_timer) != 0) {
  1121.         /* Reset the interface timer */
  1122.         ds->ds_if.if_timer = DU_HZ;
  1123.         splx(s);
  1124.         continue;
  1125.     }
  1126.  
  1127.     /* If the call failed, allow new calls to be made. */
  1128.     if (ds->ds_flags & DS_FAILCALL)
  1129.         ds->ds_flags &= ~(DS_LWAITING|DS_LACTIVE|DS_LDOWN|DS_FAILCALL);
  1130.  
  1131.     /* Trying to get a line - timeout. */
  1132.     if (ds->ds_flags & DS_LWAITING) {
  1133.         /* we never had a line, just tidy the net */
  1134.         DDEBUG(D_TRACE, "dutimer: unit %d - we never had a line.\n",
  1135.         i, 0, 0);
  1136.         dutnetclose(ds);
  1137.         ds->ds_flags &= ~(DS_LWAITING|DS_LACTIVE|DS_LDOWN|DS_FAILCALL);
  1138.     }
  1139.  
  1140.     /* Is the line to be shutdown? */
  1141.     if (ds->ds_flags & DS_LDOWN) {
  1142.         DDEBUG(D_TRACE, "dutimer: unit %d - shutdown net and line.\n",
  1143.             i, 0, 0);
  1144.         dutnetclose(ds);
  1145.         if (ds->ds_ttyp)
  1146.         /* just being careful */
  1147.         dutclose(ds->ds_ttyp);
  1148.         ds->ds_flags &= ~(DS_LWAITING|DS_LACTIVE|DS_LDOWN|DS_FAILCALL);
  1149.     }
  1150.  
  1151.     /* inactivity timer just went off - shutdown the line */
  1152.     if (ds->ds_flags & DS_LACTIVE) {
  1153.         /* mistaken? */
  1154.         if (ds->ds_flags & DS_OACTIVE)
  1155.         ds->ds_timer = -1;
  1156.         else {
  1157.         DDEBUG(D_TRACE, "dutimer: unit %d - bringing down line.\n",
  1158.             i, 0, 0);
  1159.         dutnetclose(ds);
  1160.         if (ds->ds_ttyp)
  1161.             dutclose(ds->ds_ttyp);
  1162.         }
  1163.     }
  1164.     splx(s);
  1165.     }
  1166. }
  1167.  
  1168.  
  1169. #ifndef    vax
  1170. /*
  1171. **  locc appears to only be in 4.3 for vaxen
  1172. */
  1173. int
  1174. locc(mask, size, cp)
  1175.     register u_char mask;
  1176.     u_int size;
  1177.     register u_char *cp;
  1178. {
  1179.     register u_char *end;
  1180.  
  1181.     for (end = &cp[size]; cp < end && *cp != mask; cp++)
  1182.     ;
  1183.     return(end - cp);
  1184. }
  1185. #endif    /* vax*/
  1186.  
  1187. #endif /* NDU > 0 */
  1188.